﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.Cloud.Collections
{
    /// <summary>
    /// IAsyncDictionary is an interface for handling data stored on a remote machine.
    /// Semantics are inspired by IDictionary, but are slightly different.
    /// Since we expect multiple clients to be updating a dictionary simultaneously,
    /// the idea of distinguishing between an Add operation vs. a Set operation is silly - any 
    /// solution relying on that distinction is prone to races.
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
#if CONTRACTS_FULL    
    [ContractClass(typeof(IDictionaryAsyncContract<,>))]
#endif // CONTRACTS_FULL
    public interface IDictionaryAsync<TKey, TValue> : ICollectionAsync<KeyValuePair<TKey, TValue>>
    {
        Task<TValue> GetValueAsync(TKey key);
        Task SetValueAsync(TKey key, TValue value);
        Task<Tuple<bool, TValue>> TryGetValueAsync(TKey key);  // Goofy...

        // @TODO: Add some appropriate version(s) of these methods from ConcurrentDictionary.  Perhaps overloads taking a pre-made TValue?
        //Task<TValue> AddOrUpdateAsync(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateFactory);
        //Task<TValue> GetOrAddAsync(TKey key, Func<TKey, TValue> valueFactory);

        // No AddAsync - use SetValueAsync instead.  We have no atomic operation to add iff a value is not in the dictionary.
        //Task AddAsync(TKey key, TValue value);
        Task<bool> ContainsKeyAsync(TKey key);
        Task<bool> RemoveAsync(TKey key);

        // Bulk operations
        Task<ICollection<TValue>> GetValuesAsync(IEnumerable<TKey> keys);
        Task SetValuesAsync(IEnumerable<TKey> keys, IEnumerable<TValue> values);
        Task RemoveAsync(IEnumerable<TKey> keys);

        // @TODO: SubscribeKeys and SubscribeValues instead?  Snapshot semantics, or dynamically updating?
        ICollection<TKey> Keys { get; }
        ICollection<TValue> Values { get; }
    }

#if CONTRACTS_FULL
    [ContractClassFor(typeof(IDictionaryAsync<,>))]
    public abstract class IDictionaryAsyncContract<TKey, TValue> : IDictionaryAsync<TKey, TValue>
    {
        public TimeSpan Timeout
        {
            get;
            set;
        }

        public Task<TValue> GetValueAsync(TKey key)
        {
            Contract.Requires<ArgumentNullException>(key != null);
            return null;
        }

        public Task SetValueAsync(TKey key, TValue value)
        {
            Contract.Requires<ArgumentNullException>(key != null);
            throw new NotImplementedException();
        }

        public Task<Tuple<bool, TValue>> TryGetValueAsync(TKey key)
        {
            Contract.Requires<ArgumentNullException>(key != null);

            throw new NotImplementedException();
        }

        public Task<bool> ContainsKeyAsync(TKey key)
        {
            Contract.Requires<ArgumentNullException>(key != null);

            throw new NotImplementedException();
        }

        public Task<bool> ContainsValueAsync(TValue value)
        {
            throw new NotImplementedException();
        }

        public Task<bool> RemoveAsync(TKey key)
        {
            Contract.Requires<ArgumentNullException>(key != null);

            throw new NotImplementedException();
        }

        public Task<ICollection<TValue>> GetValuesAsync(IEnumerable<TKey> keys)
        {
            Contract.Requires<ArgumentNullException>(keys != null);
            Contract.Requires(Contract.ForAll(keys, k => k != null));

            throw new NotImplementedException();
        }

        public Task SetValuesAsync(IEnumerable<TKey> keys, IEnumerable<TValue> values)
        {
            Contract.Requires<ArgumentNullException>(keys != null);
            Contract.Requires<ArgumentNullException>(values != null);
            Contract.Requires(Contract.ForAll(keys, k => k != null));

            throw new NotImplementedException();
        }

        public Task RemoveAsync(IEnumerable<TKey> keys)
        {
            Contract.Requires<ArgumentNullException>(keys != null);
            Contract.Requires(Contract.ForAll(keys, k => k != null));

            throw new NotImplementedException();
        }

        public ICollection<TKey> Keys
        {
            get { throw new NotImplementedException(); }
        }

        public ICollection<TValue> Values
        {
            get { throw new NotImplementedException(); }
        }

    #region Inherited methods

        public Task<int> CountAsync
        {
            get { throw new NotImplementedException(); }
        }

        public Task<bool> IsReadOnlyAsync
        {
            get { throw new NotImplementedException(); }
        }

        public Task AddAsync(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public Task ClearAsync()
        {
            throw new NotImplementedException();
        }

        public Task<bool> ContainsAsync(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public Task CopyToAsync(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public Task<bool> RemoveAsync(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public IDisposable Subscribe(IObserver<KeyValuePair<TKey, TValue>> observer)
        {
            throw new NotImplementedException();
        }

    #endregion Inherited methods
    }
#endif // CONTRACTS_FULL
}
